#pragma once

#include <iostream>
#include <memory>
#include "Log.hpp"
#include "Socket.hpp"
#include "Epoller.hpp"

class EpollServer : public noncopy
{
public:
    static const uint16_t default_port = 8080;
    // static const int epoll_size = 128;       // 只在Epoller中使用，无需写于此处
    static const int max_events = 64;

    // int event_in = (EPOLLIN);
    // int event_out = (EPOLLOUT);

    uint32_t event_in = (EPOLLIN);
    uint32_t event_out = (EPOLLOUT);

    EpollServer(uint16_t port = default_port)
        : _port(port),
          _listensock_ptr(new Socket()),
          _epoller_ptr(new Epoller())
    {
    }

    void Initial()
    {
        _listensock_ptr->CreateSock();
        _listensock_ptr->Bind(_port);
        _listensock_ptr->Listen();
        lg(Info, "create listen sock success, fd: %d", _listensock_ptr->GetSockFd());
    }

    void Accept()
    {
        std::string clientip;
        uint16_t clientport;
        int fd = _listensock_ptr->Accept(&clientip, &clientport);
        if (fd < 0)
            return;
        _epoller_ptr->EpollControl(EPOLL_CTL_ADD, fd, event_in);
        lg(Info, "accept success, fd: %d", fd); // 添加完再输出消息
    }

    // void Receive(int fd, int pos)
    void Receive(int fd) // 不需要pos参数
    {
        char buffer[1024];
        ssize_t sz = read(fd, buffer, sizeof(buffer) - 1);
        if (sz > 0)
        {
            buffer[sz] = 0;
            std::cout << "server get a message: " << buffer << std::endl;
            std::string echo_str = "server: ";
            echo_str += buffer;
            sz = write(fd, echo_str.c_str(), echo_str.size());
            if (sz < 0)
                lg(Error, "fd: %d, write error", fd);
        }
        else if (sz == 0)
        {
            lg(Info, "client quit, fd: %d close", fd);
            _epoller_ptr->EpollControl(EPOLL_CTL_DEL, fd, 0);
            close(fd); // 需先从epoll中移除再关闭文件描述符，否则EpollControl将移除出错
        }
        else
        {
            lg(Error, "read error, fd: %d, errno: %d, error string: %s", fd, errno, strerror(errno));
            _epoller_ptr->EpollControl(EPOLL_CTL_DEL, fd, 0);
            close(fd);
        }
    }

    // void Dispatch(struct epoll_event *events, int num)
    void Dispatch(struct epoll_event events[], int num) // 可写成数组，方便理解
    {
        for (int i = 0; i < num; ++i)
        {
            int fd = events[i].data.fd;
            if (events[i].events & event_in)
            {
                if (fd == _listensock_ptr->GetSockFd())
                    Accept();
                else
                    Receive(fd);
            }
            else // out或者其他情况
            {
            }
        }
    }

    void Start()
    {
        _epoller_ptr->EpollControl(EPOLL_CTL_ADD, _listensock_ptr->GetSockFd(), event_in);
        struct epoll_event events[max_events];
        for (;;)
        {
            int n = _epoller_ptr->EpollWait(events, max_events);
            switch (n)
            {
            case 0:
                lg(Info, "timeout");
                break;
            case -1:
                lg(Error, "epoll error");
                break;
            default:
                lg(Info, "epoll waite success");
                Dispatch(events, n);
                break;
            }
        }
    }

    ~EpollServer()
    {
        _listensock_ptr->Close();
    }

private:
    std::shared_ptr<Socket> _listensock_ptr;
    std::shared_ptr<Epoller> _epoller_ptr;
    uint16_t _port;
};